#include <utility>
#include "FLOW_ents/namespace.h"
#include "FLOW_ents/Entity.h"
#include "FLOW_core/core_types.h"
#include "FLOW_core/mem.h"
#include "FLOW_core/utils.h"

using namespace CORE;

namespace ENTS
{
	//=========================================================================

	CEntity::CEntity( )
		: m_b_enabled( true )
	{
	}

	//=========================================================================

	CEntity::CEntity( const CStrId& ar_entity_id )
		: m_entity_id( ar_entity_id )
	{
	}

	//=========================================================================

	// Entity destructor doesn't detroy components because components may be shared
	// Use method DeleteComponents to force the destruction of the components of an entity
	CEntity::~CEntity( )
	{
		m_hmm_components.clear( );
	}

	//=========================================================================

	void CEntity::CloneComponentsFrom( const CEntity& ar_ent )
	{
		CmpntHashMultiMap::const_iterator it = ar_ent.m_hmm_components.begin( );
		CmpntHashMultiMap::const_iterator end = ar_ent.m_hmm_components.end( );

		for( ; it != end; ++it )
		{
			CComponent* p_cloned = it->second->Clone( );
			Add( p_cloned, false );
		}

		it = m_hmm_components.begin( );
		end = m_hmm_components.end( );

		for( ; it != end; ++it )
			it->second->CheckBindings( );
	}

	//=========================================================================

	CEntity::CEntity( const CEntity& ar_ent )
	{
		m_entity_id = ar_ent.m_entity_id;

		CloneComponentsFrom( ar_ent );
	}

	//=========================================================================

	CEntity& CEntity::operator =( const CEntity& ar_ent )
	{
		m_entity_id = ar_ent.m_entity_id;

		CloneComponentsFrom( ar_ent );

		return *this;
	}

	//=========================================================================

	void CEntity::Update( void )
	{
		if( !m_b_enabled )
			return;

		CmpntPriorityOrderedSet::iterator it = m_s_components.begin( );
		CmpntPriorityOrderedSet::iterator end = m_s_components.end( );

		for( ; it != end; ++it )
			(*it)->Update( );
	}

	//=========================================================================

	bool_t CEntity::Add( CComponent* ap_component, bool_t ab_bind_on_addition )
	{
		if( !ap_component )
			return false;

		std::pair< CmpntPriorityOrderedSet::iterator , bool_t > set_result = m_s_components.insert( ap_component );
		if( !set_result.second )
			return false;

		CORE::CStrId cmpnt_class_name( ap_component->GetClassRTTI( )->GetClassName( ) );
		CmpntHashMultiMap::iterator hmm_result = m_hmm_components.insert( std::pair< const u32_t, CComponent* >( cmpnt_class_name.Hash( ), ap_component ) );
		if( hmm_result == m_hmm_components.end( ) )
		{
			m_s_components.erase( set_result.first );
			return false;
		}

		if( ab_bind_on_addition )
			ap_component->CheckBindings( );

		return true;
	}

	//=========================================================================

	bool_t CEntity::Remove( CComponent* ap_component )
	{
		if( !ap_component )
			return false;

		CStrId cmpnt_class_name = ap_component->GetClassRTTI( )->GetClassName( );

		m_s_components.erase( ap_component );

		CmpntHashMultiMap::iterator found = m_hmm_components.find( cmpnt_class_name.Hash( ) );
		if( found != m_hmm_components.end( ) )
		{
			m_hmm_components.erase( found );
			return true;
		}

		return false;
	}

	//=========================================================================

	CEntity* CEntity::Clone( void )
	{
		CEntity* p_new_ent = new CEntity( );

		p_new_ent->CloneComponentsFrom( *this );
		p_new_ent->m_entity_id = m_entity_id;
		return p_new_ent;
	}

	//=========================================================================

	void CEntity::DeleteComponents( void )
	{
		CmpntHashMultiMap::iterator it = m_hmm_components.begin( );
		CmpntHashMultiMap::iterator end = m_hmm_components.end( );

		for( ; it != end; ++it )
			SAFE_DELETE( it->second );
	}

	//=========================================================================

	void CEntity::Swap( CEntity* ap_entity )
	{
		if( !ap_entity )
			return;

		m_hmm_components.swap( ap_entity->m_hmm_components );
		m_s_components.swap( m_s_components );
		CStrId swap_strid( m_entity_id );
		ap_entity->m_entity_id = m_entity_id;
		m_entity_id = swap_strid;
	}

	//=========================================================================

	CStrId CEntity::GetName( void )
	{
		return m_entity_id;
	}

	//=========================================================================

	void CEntity::SetName( const char_t* apsz_entity_name )
	{
		if( SzCheck( apsz_entity_name ) )
			m_entity_id	= apsz_entity_name;
	}

	//=========================================================================

	void CEntity::SetEnabled( bool_t ab_enabled )
	{
		m_b_enabled = ab_enabled;
	}

	//=========================================================================

	bool_t CEntity::IsEnabled( void )
	{
		return m_b_enabled;
	}

	//=========================================================================

	
} //namespace ENTS